在深入MySQL之前, 不妨分析一下如下的sql語句是如何在MySQL執行的呢?
? ? ? ? select * from t where id = 10 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?語句1
? ? ? ? 想要清晰的了解這條語句在MySQL的內部執行流程,則必須要先了解MySQL的基礎架構組成
MySQL由以下幾個部分組成:
? ? ? ? 1、客戶端: 客戶端連接器(Client)對MySQL的服務層(MySQL Server)進行接入
? ? ? ? 2、MySQL Server: 包括SQL接口、連接池、緩存、解析器、優化器、執行器等, 所有跨存儲引擎的功能都在這一層實現,比如存儲過程、觸發器、視圖等
? ? ? ? 3、存儲引擎: MySQL Server通過接口, 實現對各類不同存儲引擎的支持
? ? ? ? 4、生成系統文件, ?包括文件和日志
? ? ? ? MySQL Server層中的各種應用又提供了哪些功能呢??
? ? ? ? 1、連接池:
? ? ? ? ?顧名思義, 它提供了客戶端與MySQL建立連接的功能, ?MySQL既支持長連接, 也支持短連接; ?通常我們在連接池中采用長連接的方式以提升連接的復用效率, 但是保持長連接會消耗內存, 當內存消耗達到一定程度時, MySQL會被系統強制crash, 因此在開發過程中, 我們通常采用以下兩種方案來解決此類問題:
? ? ? ? (1) 定期斷開長連接。使用一段時間,或者程序里面判斷執行過一個占用內存的大查詢后,斷開 連接,之后要查詢再重連。
? ? ? ? (2) 如果MySQL的版本是MySQL5.7及以上,可以在每次執行一個比較大的操作后,通過執行 mysql_reset_connection來重新初始化連接資源。這個過程不需要重連和重新做權限驗證, 但是會將連接恢復到剛剛創建完時的狀態。
? ? ? ? 2、SQL接口: ?
? ? ? ? SQL接口中涵蓋MySQL的大多數核心服務功能,以及所有的內置函數(如日期、時間、數學和加密函數等)
? ? ? ? 3、緩存:
? ? ? ? 連接建立完成后,就可以執行sql語句了。此時執行邏輯就會來到第二步: 查詢緩存。MySQL拿到語句1請求后,會先到查詢緩存看看,之前是不是執行過這條語句。之前執行過的語句及其結果以key-value對的形式,被直接緩存在內存中。如果語句1之前被查詢過,則語句1作為key,語句1的查詢結果作為value。這樣就可以通過查詢緩存中的key快速的取到與之對應的value并返回給客戶端,如果語句1不在查詢緩存中,就會繼續后面的執行階段。執行完成后,執行結果會被存入查詢緩存中。
? ? ? ? 但是大多數情況下不會使用查詢緩存,因為緩存的失效非常頻繁,只要有對一個表的更新,這個表上所有的查詢緩存都會被清空。那么在什么場景下我們會使用查緩存的方式呢?
? ? ? ? 當你的業務就是有一張靜態表,很長時間才會更新一次。 比如,一個系統配置表,那這張表上的查詢才適合使用查詢緩存。 在MySQL8.0之后,緩存應用塊就已經被移除。
? ? ? ? 4、解析器
? ? ? ? 當語句1沒有命中查詢緩存時,就開始真正的對語句1進行執行,此時解析器開始工作。解析器的主要工作就是對sql語句進行解析,首先判斷sql語句的合法性,其次判斷sql要實現什么功能,比如增刪改查等。
? ? ? ? 5、優化器
? ? ? ? 在sql語句經過解析器之后,還需要經過優化器來對此語句進行優化處理。
? ? ? ? 優化器是在表里面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)
的時候,決定各個表的連接順序。
? ? ? ? 比如你執行語句2的連表查詢時,
? ? ? ? select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20 ? ? ? ? ? ? 語句2
? ? ? ? 既可以先從表t1里面取出c=10的記錄的ID值,再根據ID值關聯到表t2,再判斷t2里面d的值是 否等于20。 也可以先從表t2里面取出d=20的記錄的ID值,再根據ID值關聯到t1,再判斷t1里面c的值是否 等于10。
? ? ? ? 這兩種執行方法的邏輯結果是一樣的,但是執行的效率會有不同,而優化器的作用就是決定選擇使用哪一個方案。
? ? ? ? 6、執行器
? ? ? ? MySQL通過解析器知道了你要做什么,通過優化器知道了該怎么做,于是就進入了執行器階 段,開始執行語句。
? ? ? ? 開始執行的時候,要先判斷一下你對這個表T有沒有執行查詢的權限,如果沒有,就會返回沒有 權限的錯誤,如下所示。
? ? ? ? 如果有權限,就打開表繼續執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引 擎提供的接口。
? ? ? ? 比如我們這個例子中的表T中,ID字段沒有索引,那么執行器的執行流程是這樣的:
? ? ? ? 1. 調用InnoDB引擎接口取這個表的第一行,判斷ID值是不是10,如果不是則跳過,如果是則將這行存在結果集中;
? ? ? ? 2. 調用引擎接口取“下一行”,重復相同的判斷邏輯,直到取到這個表的最后一行。
? ? ? ? 3. 執行器將上述遍歷過程中所有滿足條件的行組成的記錄集作為結果集返回給客戶端。
? ? ? ? 至此,這個語句就執行完成了。 對于有索引的表,執行的邏輯也差不多。第一次調用的是“取滿足條件的第一行”這個接口,之后循環取“滿足條件的下一行”這個接口,這些接口都是引擎中已經定義好的。 你會在數據庫的慢查詢日志中看到一個rows_examined的字段,表示這個語句執行過程中掃描了多少行。這個值就是在執行器每次調用引擎獲取數據行的時候累加的。
?
?